﻿'TODO: Document Move Control
''' <summary>
''' This class is used to enable run-time moving of controls. Set the design surface as the parent control on
''' your form that will contain all the controls you want to be allow user to move at run-time.
''' The DesignSurface you set will essentially limit the user to only move control within that design surface.
''' To have a control at runtime become user moveable, simply set the BoundControl of this class to the control
''' you want. 
''' Note that this class supports reparenting of moved controls. To allow other controls on your design surface to capture
''' a control when it is moved there, set those controls' AllowDrop property to True.
''' </summary>
''' <remarks></remarks>
Public Class MoveControl
#Region "Private Attributes"
    Private _BoundControl As Control
    Private _DesignSurface As Control
    Private _BoundControlDockStyle As System.Windows.Forms.DockStyle
    Private _BoundControlAnchorFlags As System.Windows.Forms.AnchorStyles

    Private _IsMoving As Boolean = False
    Private _MoveStartMouseLocationScr As Point = Nothing
    Private _MoveStartCtlLocationScr As Point = Nothing
    Private _NeedsReparenting As Boolean = False

    Private _OuterFrameRect As Rectangle

    Private _MoveGlyphSize As Integer = 15
    Private _MoveGlyphXOffset As Integer = 5
    Private _MoveGlyphRect As Rectangle

    Private _CtlPanel As New Panel

    Private _DesignerControls As List(Of SnapControl)
    Private _ProximitySnap As Integer = 4

    Private Enum ClosestPointsX As Integer
        LeftLeft = 0
        LeftRight = 1
        RightLeft = 2
        RightRight = 3
    End Enum
    Private Enum ClosestPointsY As Integer
        TopTop = 0
        TopBottom = 1
        BottomTop = 2
        BottomBottom = 3
    End Enum
#End Region

#Region "Public Interface"
    ''' <summary>
    ''' Creates a new run-time Moving control. The moving control does not become "active" on the design surface at run-time
    ''' until it has been bound to the control that needs to be moved. (Using the BoundControl property).
    ''' </summary>
    ''' <param name="DesignSurface"></param>
    ''' <remarks></remarks>
    Public Sub New(ByVal DesignSurface As Control)
        ' Add any initialization after the InitializeComponent() call.
        _CtlPanel.BackColor = Color.White

        _CtlPanel.Size = New Size(_MoveGlyphSize, _MoveGlyphSize)

        _DesignSurface = DesignSurface


        'Add Event Handlers
        AddHandler _CtlPanel.MouseEnter, AddressOf MouseEnter_MoveGlyph
        AddHandler _CtlPanel.MouseLeave, AddressOf MouseLeave_MoveGlyph
        AddHandler _CtlPanel.MouseDown, AddressOf MouseDown_MoveGlyph
        AddHandler _CtlPanel.MouseUp, AddressOf MouseUp_MoveGlyph
        AddHandler _CtlPanel.MouseMove, AddressOf MouseMove_MoveGlyph
        AddHandler _CtlPanel.Paint, AddressOf OnPaint

    End Sub

    ''' <summary>
    ''' Returns the Design Surface this Moving control has been bound to. All Move operations will be performed within the
    ''' Design surface context.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property DesignSurface() As Control
        Get
            Return _DesignSurface
        End Get
    End Property

    ''' <summary>
    ''' Used to set which control should become moveable. Set this value to nothing to "turn off" moving functionality or set to
    ''' a new control to enable moving functionality for that control.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property BoundControl() As Control
        Get
            Return _BoundControl
        End Get
        Set(ByVal value As Control)
            If value Is Nothing Then
                'Turn off this move control
                If _DesignSurface.Controls.Contains(_CtlPanel) Then
                    _DesignSurface.Controls.Remove(_CtlPanel)
                End If
                If _BoundControl IsNot Nothing Then
                    RemoveHandler _BoundControl.SizeChanged, AddressOf ControlResized
                    RemoveHandler _BoundControl.LocationChanged, AddressOf ControlLocationChanged
                End If
                _BoundControl = Nothing
            Else
                If _BoundControl Is Nothing Then
                    'Binding a control for first time
                    If Not _DesignSurface.Controls.Contains(_CtlPanel) Then _DesignSurface.Controls.Add(_CtlPanel)
                    AddHandler value.SizeChanged, AddressOf ControlResized
                    AddHandler value.LocationChanged, AddressOf ControlLocationChanged
                    _BoundControlAnchorFlags = value.Anchor
                    _BoundControlDockStyle = value.Dock
                ElseIf _BoundControl IsNot value Then
                    'Binding to a new control
                    RemoveHandler _BoundControl.SizeChanged, AddressOf ControlResized
                    RemoveHandler _BoundControl.LocationChanged, AddressOf ControlLocationChanged
                    If Not (_DesignSurface.Controls.Contains(_CtlPanel)) Then _DesignSurface.Controls.Add(_CtlPanel)
                    AddHandler value.SizeChanged, AddressOf ControlResized
                    AddHandler value.LocationChanged, AddressOf ControlLocationChanged
                    _BoundControlAnchorFlags = value.Anchor
                    _BoundControlDockStyle = value.Dock
                Else
                    'Binding to same control again
                    RemoveHandler _BoundControl.SizeChanged, AddressOf ControlResized
                    RemoveHandler _BoundControl.SizeChanged, AddressOf ControlResized
                    If Not (_DesignSurface.Controls.Contains(_CtlPanel)) Then _DesignSurface.Controls.Add(_CtlPanel)
                    AddHandler value.SizeChanged, AddressOf ControlResized
                    AddHandler value.LocationChanged, AddressOf ControlLocationChanged
                End If
                _BoundControl = value
                value.BringToFront()
                RedrawGlyph(False, Nothing, Nothing, False, Nothing, Nothing)
            End If

            _CtlPanel.BringToFront()
            'Me.Refresh()
        End Set
    End Property

    ''' <summary>
    ''' Used to set proximity snapping. Set to 0 to turn proximity snapping off.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property ProximitySnapSize() As Integer
        Get
            Return _ProximitySnap
        End Get
        Set(ByVal value As Integer)
            _ProximitySnap = value
        End Set
    End Property

    ''' <summary>
    ''' Sets the size (in pixels) of the Move glyph that appears at the top left of the control 
    ''' that has been move-enabled (using the BoundControl property)
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property MoveGlyphSize() As Integer
        Get
            Return _MoveGlyphSize
        End Get
        Set(ByVal value As Integer)
            _MoveGlyphSize = value
            RedrawGlyph(False, Nothing, Nothing, False, Nothing, Nothing)
        End Set
    End Property

    ''' <summary>
    ''' The Move glyph is positioned to the right of the top left corner of the move-enabled control.
    ''' This offset determines how far to the right of that top left corner the Move glyph should be positioned.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property MoveGlyphOffset() As Integer
        Get
            Return _MoveGlyphXOffset
        End Get
        Set(ByVal value As Integer)
            _MoveGlyphXOffset = value
            RedrawGlyph(False, Nothing, Nothing, False, Nothing, Nothing)
        End Set
    End Property
#End Region

#Region "Private Methods"
    Private Sub CalculateAllBounds()
        'Outer Frame

        If _BoundControl IsNot Nothing Then
            _OuterFrameRect = _DesignSurface.RectangleToClient(_BoundControl.Parent.RectangleToScreen(_BoundControl.Bounds))

            _MoveGlyphRect = New Rectangle(_OuterFrameRect.X + _MoveGlyphXOffset + _MoveGlyphSize \ 2, _OuterFrameRect.Y - _MoveGlyphSize \ 2, _MoveGlyphSize, _MoveGlyphSize)
        End If
    End Sub
    Private Sub RedrawGlyph(ByVal DrawVSnapLine As Boolean, ByVal VSnapLineStart As Point, ByVal VSnapLineEnd As Point, ByVal DrawHSnapLine As Boolean, ByVal HSnapLineStart As Point, ByVal HSnapLineEnd As Point)
        CalculateAllBounds()
        If _BoundControl IsNot Nothing Then
            'Move Glyph
            With _CtlPanel
                .BackColor = Color.White
                .AutoSize = False
                .Location = _MoveGlyphRect.Location
                .Size = _MoveGlyphRect.Size
                ControlPaint.DrawContainerGrabHandle(_CtlPanel.CreateGraphics, _CtlPanel.ClientRectangle)
                .BringToFront()
            End With
            'If DrawVSnapLine OrElse DrawHSnapLine Then
            '    Dim myG As Graphics = _DesignSurface.CreateGraphics
            '    If DrawVSnapLine Then
            '        myG.DrawLine(Pens.BlueViolet, VSnapLineStart, VSnapLineEnd)
            '    End If
            '    If DrawHSnapLine Then
            '        myG.DrawLine(Pens.BlueViolet, HSnapLineStart, HSnapLineEnd)
            '    End If
            'Else
            '    _DesignSurface.Invalidate()
            'End If
            _DesignSurface.Invalidate()
        Else
            If _DesignSurface.Controls.Contains(_CtlPanel) Then
                _DesignSurface.Controls.Remove(_CtlPanel)
                _DesignSurface.Refresh()
            End If
        End If
        _CtlPanel.BringToFront()
    End Sub

    Private Function FindNewParent(ByVal SourceCtl As Control, ByVal DroppedCtl As Control, ByVal CursorScreenLoc As Point) As Control
        Dim TargetCtl As Control = Nothing
        'Find any control contained on designsurface that contains the current cursor position
        For Each Ctl As Control In SourceCtl.Controls
            If Ctl IsNot DroppedCtl AndAlso Ctl.AllowDrop Then
                If Ctl.RectangleToScreen(Ctl.ClientRectangle).Contains(CursorScreenLoc) Then
                    'Ctl contains cursor - but does it have any child controls that contain the cursor?
                    'Recurse to find out
                    TargetCtl = FindNewParent(Ctl, DroppedCtl, CursorScreenLoc)
                    If TargetCtl Is Nothing Then
                        'No child parent controls found
                        TargetCtl = Ctl
                        Exit For
                    End If
                End If
            End If
        Next
        Return TargetCtl
    End Function
    Private Sub FindDesignerControls()
        'Finds other Layout enabled designer controls...
        If _DesignerControls IsNot Nothing Then
            For Each Ctl As SnapControl In _DesignerControls
                Ctl = Nothing
            Next
            _DesignerControls.Clear()
        End If
        _DesignerControls = FindChildControls(_DesignSurface)

    End Sub
    Private Function FindChildControls(ByVal RootControl As Control) As List(Of SnapControl)
        Dim myList As New List(Of SnapControl)

        For Each Ctl As Control In RootControl.Controls
            If Ctl IsNot _BoundControl And Not String.IsNullOrEmpty(Ctl.Name) Then
                myList.Add(New SnapControl(Ctl, Ctl.Parent.PointToScreen(Ctl.Location), Ctl.Size))
                myList.AddRange(FindChildControls(Ctl))
            End If
        Next

        Return myList
    End Function

    Private Function ProximitySnap(ByVal CurrScreenLoc As Point, _
                                  ByVal CurrSize As Size, _
                                  ByVal Controls As List(Of SnapControl), _
                                  ByRef VSnapLine As Boolean, _
                                  ByRef VSnapLineStart As Point, _
                                  ByRef VSnapLineEnd As Point, _
                                  ByRef HSnapLine As Boolean, _
                                  ByRef HSnapLineStart As Point, _
                                  ByRef HSnapLineEnd As Point) As Point

        Dim SnapPoint As Point = Nothing
        'X Proximity Snapping
        Dim LeftX_LeftX As Integer = 0
        Dim LeftX_RightX As Integer = 0
        Dim RightX_LeftX As Integer = 0
        Dim RightX_RightX As Integer = 0
        Dim ClosestPointX As ClosestPointsX = Nothing
        Dim ClosestDistX As Integer = Integer.MaxValue
        Dim MinClosestDistX As Integer = ClosestDistX
        Dim XSnapCtl As SnapControl = Nothing

        'Y Proximity Snapping
        Dim TopY_TopY As Integer = 0
        Dim TopY_BottomY As Integer = 0
        Dim BottomY_TopY As Integer = 0
        Dim BottomY_BottomY As Integer = 0
        Dim ClosestPointY As ClosestPointsY = Nothing
        Dim ClosestDistY As Integer = Integer.MaxValue
        Dim MinClosestDistY As Integer = ClosestDistY
        Dim YSnapCtl As SnapControl = Nothing

        'Initialize Snap Point to current location
        SnapPoint.X = CurrScreenLoc.X
        SnapPoint.Y = CurrScreenLoc.Y

        VSnapLine = False

        For Each Ctl As SnapControl In Controls
            'X Proximity Snapping
            LeftX_LeftX = Math.Abs(CurrScreenLoc.X - Ctl.ScreenLoc.X)
            If LeftX_LeftX < ClosestDistX Then
                ClosestPointX = ClosestPointsX.LeftLeft
                ClosestDistX = LeftX_LeftX
            End If

            LeftX_RightX = Math.Abs(CurrScreenLoc.X - (Ctl.ScreenLoc.X + Ctl.Size.Width))
            If LeftX_RightX < ClosestDistX Then
                ClosestPointX = ClosestPointsX.LeftRight
                ClosestDistX = LeftX_RightX
            End If

            RightX_LeftX = Math.Abs(Ctl.ScreenLoc.X - (CurrScreenLoc.X + CurrSize.Width))
            If RightX_LeftX < ClosestDistX Then
                ClosestPointX = ClosestPointsX.RightLeft
                ClosestDistX = RightX_LeftX
            End If

            RightX_RightX = Math.Abs(Ctl.ScreenLoc.X + Ctl.Size.Width - (CurrScreenLoc.X + CurrSize.Width))
            If RightX_RightX < ClosestDistX Then
                ClosestPointX = ClosestPointsX.RightRight
                ClosestDistX = RightX_RightX
            End If

            If ClosestDistX < _ProximitySnap AndAlso ClosestDistX < MinClosestDistX Then
                'This is a new closer location that is also within snapping threshold
                VSnapLine = True
                XSnapCtl = Ctl
                'Snap to this X location
                Select Case ClosestPointX
                    Case ClosestPointsX.LeftLeft
                        SnapPoint.X = Ctl.ScreenLoc.X
                    Case ClosestPointsX.LeftRight
                        SnapPoint.X = Ctl.ScreenLoc.X + Ctl.Size.Width
                    Case ClosestPointsX.RightLeft
                        SnapPoint.X = Ctl.ScreenLoc.X - CurrSize.Width
                    Case ClosestPointsX.RightRight
                        SnapPoint.X = Ctl.ScreenLoc.X + Ctl.Size.Width - CurrSize.Width
                End Select
                MinClosestDistX = ClosestDistX
            End If

            'Y Proximity Snapping
            TopY_TopY = Math.Abs(CurrScreenLoc.Y - Ctl.ScreenLoc.Y)
            If TopY_TopY < ClosestDistY Then
                ClosestPointY = ClosestPointsY.TopTop
                ClosestDistY = TopY_TopY
            End If

            TopY_BottomY = Math.Abs(CurrScreenLoc.Y - (Ctl.ScreenLoc.Y + Ctl.Size.Height))
            If TopY_BottomY < ClosestDistY Then
                ClosestPointY = ClosestPointsY.TopBottom
                ClosestDistY = TopY_BottomY
            End If

            BottomY_TopY = Math.Abs(CurrScreenLoc.Y + CurrSize.Height - Ctl.ScreenLoc.Y)
            If BottomY_TopY < ClosestDistY Then
                ClosestPointY = ClosestPointsY.BottomTop
                ClosestDistY = BottomY_TopY
            End If

            BottomY_BottomY = Math.Abs(CurrScreenLoc.Y + CurrSize.Height - (Ctl.ScreenLoc.Y + Ctl.Size.Height))
            If BottomY_BottomY < ClosestDistY Then
                ClosestPointY = ClosestPointsY.BottomBottom
                ClosestDistY = BottomY_BottomY
            End If

            If ClosestDistY < _ProximitySnap AndAlso ClosestDistY < MinClosestDistY Then
                'This is a new closer location that is also within snapping threshold
                HSnapLine = True
                YSnapCtl = Ctl
                'Snap to this Y location
                Select Case ClosestPointY
                    Case ClosestPointsY.TopTop
                        SnapPoint.Y = Ctl.ScreenLoc.Y
                    Case ClosestPointsY.TopBottom
                        SnapPoint.Y = Ctl.ScreenLoc.Y + Ctl.Size.Height
                    Case ClosestPointsY.BottomTop
                        SnapPoint.Y = Ctl.ScreenLoc.Y - CurrSize.Height
                    Case ClosestPointsY.BottomBottom
                        SnapPoint.Y = Ctl.ScreenLoc.Y + Ctl.Size.Height - CurrSize.Height
                End Select
                MinClosestDistY = ClosestDistY
            End If
        Next 'Control


        If VSnapLine Then
            'Snapping along X axis
            Dim X As Integer = 0
            Dim Y1 As Integer = 0
            Dim Y2 As Integer = 0

            If CurrScreenLoc.Y < XSnapCtl.ScreenLoc.Y Then
                'Snapping to Control below
                Y1 = SnapPoint.Y
                Y2 = XSnapCtl.ScreenLoc.Y + XSnapCtl.Size.Height
            Else
                'Snapping to control above
                Y1 = XSnapCtl.ScreenLoc.Y
                Y2 = SnapPoint.Y + CurrSize.Height
            End If

            Select Case ClosestPointX
                Case ClosestPointsX.LeftLeft
                    X = XSnapCtl.ScreenLoc.X - 1
                Case ClosestPointsX.LeftRight
                    X = XSnapCtl.ScreenLoc.X + XSnapCtl.Size.Width
                Case ClosestPointsX.RightLeft
                    X = XSnapCtl.ScreenLoc.X
                Case ClosestPointsX.RightRight
                    X = SnapPoint.X + CurrSize.Width
            End Select

            VSnapLineStart = _DesignSurface.PointToClient(New Point(X, Y1))
            VSnapLineEnd = _DesignSurface.PointToClient(New Point(X, Y2))
        End If

        If HSnapLine Then
            'Snapping along Y axis
            Dim X1 As Integer = 0
            Dim X2 As Integer = 0
            Dim Y As Integer = 0

            If CurrScreenLoc.X < YSnapCtl.ScreenLoc.X Then
                'Snapping to control at right
                X1 = SnapPoint.X
                X2 = YSnapCtl.ScreenLoc.X + YSnapCtl.Size.Width
            Else
                'Snapping to control at left
                X1 = YSnapCtl.ScreenLoc.X
                X2 = SnapPoint.X + CurrSize.Width
            End If

            Select Case ClosestPointY
                Case ClosestPointsY.TopTop
                    Y = YSnapCtl.ScreenLoc.Y - 1
                Case ClosestPointsY.TopBottom
                    Y = YSnapCtl.ScreenLoc.Y + YSnapCtl.Size.Height
                Case ClosestPointsY.BottomTop
                    Y = YSnapCtl.ScreenLoc.Y
                Case ClosestPointsY.BottomBottom
                    Y = YSnapCtl.ScreenLoc.Y + YSnapCtl.Size.Height
            End Select
            HSnapLineStart = _DesignSurface.PointToClient(New Point(X1, Y))
            HSnapLineEnd = _DesignSurface.PointToClient(New Point(X2, Y))
        End If
        Return SnapPoint
    End Function

    Private Class SnapControl
        Private _Ctl As Control
        Private _ScreenLoc As Point
        Private _Size As Size
        Public Sub New(ByVal Ctl As Control, ByVal ScreenLoc As Point, ByVal Size As Size)
            _Ctl = Ctl
            _ScreenLoc = ScreenLoc
            _Size = Size
        End Sub
        Public ReadOnly Property Control() As Control
            Get
                Return _Ctl
            End Get
        End Property
        Public ReadOnly Property ScreenLoc() As Point
            Get
                Return _ScreenLoc
            End Get
        End Property
        Public ReadOnly Property Size() As Size
            Get
                Return _Size
            End Get
        End Property
    End Class
#End Region

#Region "Event Handlers"
    Private Sub MouseEnter_MoveGlyph(ByVal sender As Object, ByVal e As System.EventArgs)
        'Nothing needed here...
    End Sub
    Private Sub MouseLeave_MoveGlyph(ByVal sender As Object, ByVal e As System.EventArgs)
        'Nothing needed here...
    End Sub
    Private Sub MouseDown_MoveGlyph(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
        If e.Button = MouseButtons.Left Then
            'User starting a Move
            If Not (_IsMoving) Then
                Dim CtlLocation As Point
                CtlLocation = _BoundControl.Location

                'if Control is Docked or anchored, then these need to be removed to ensure
                'succesful move
                _BoundControl.Hide()
                _BoundControl.SuspendLayout()
                _BoundControl.Dock = DockStyle.None
                _BoundControl.Anchor = AnchorStyles.None

                If _BoundControl.Parent.GetType IsNot GetType(System.Windows.Forms.Form) Then
                    'Control needs to be parented to Form
                    CtlLocation = _DesignSurface.PointToClient(_BoundControl.Parent.PointToScreen(CtlLocation))
                    _BoundControl.Parent.Controls.Remove(_BoundControl)
                    _DesignSurface.Controls.Add(_BoundControl)
                    _BoundControl.Location = CtlLocation
                    _BoundControl.BringToFront()
                End If

                _MoveStartMouseLocationScr = System.Windows.Forms.Control.MousePosition
                _MoveStartCtlLocationScr = _DesignSurface.PointToScreen(CtlLocation)

                _IsMoving = True
                _BoundControl.ResumeLayout()
                _BoundControl.Show()
                _CtlPanel.BringToFront()

                FindDesignerControls() 'Used for proximity snapping
            End If
        End If
    End Sub
    Private Sub MouseUp_MoveGlyph(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
        'Move operation is complete
        'Was the control dropped onto a container type control?
        'If so, reparent the control to the new container

        Dim TargetCtl As Control = FindNewParent(_DesignSurface, _BoundControl, CType(sender, Control).PointToScreen(e.Location))
        If TargetCtl IsNot Nothing Then
            Dim NewLoc As Point = TargetCtl.PointToClient(_DesignSurface.PointToScreen(_BoundControl.Location))
            TargetCtl.Controls.Add(_BoundControl)
            'Change control location to drop target relative location
            _BoundControl.Location = NewLoc
            _BoundControl.BringToFront()

            _CtlPanel.BringToFront()
        End If
        'Then set Anchor and Docking styles back to original values
        _BoundControl.Anchor = Me._BoundControlAnchorFlags
        _BoundControl.Dock = Me._BoundControlDockStyle
        'Finally turn Moving off
        _IsMoving = False
        _CtlPanel.SendToBack()
        _BoundControl.Invalidate()
        '_DesignSurface.Invalidate()
    End Sub
    Private Sub MouseMove_MoveGlyph(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
        If _IsMoving Then
            Dim Offset As Point = New Point(System.Windows.Forms.Control.MousePosition.X - _MoveStartMouseLocationScr.X, System.Windows.Forms.Control.MousePosition.Y - _MoveStartMouseLocationScr.Y)
            If Offset.X = 0 AndAlso Offset.Y = 0 Then Exit Sub 'Control did not actually move

            Dim NewCtlScrLocation As Point = _MoveStartCtlLocationScr
            NewCtlScrLocation.Offset(Offset)

            Dim VSnapping As Boolean = False
            Dim VSnapLineStart As Point = Nothing
            Dim VSnapLineEnd As Point = Nothing
            Dim HSnapping As Boolean = Nothing
            Dim HSnapLineStart As Point = Nothing
            Dim HSnapLineEnd As Point = Nothing

            Dim SnapLocation As Point
            SnapLocation = ProximitySnap(NewCtlScrLocation, _BoundControl.Size, _DesignerControls, VSnapping, VSnapLineStart, VSnapLineEnd, HSnapping, HSnapLineStart, HSnapLineEnd)

            Dim NewCtlLocation As Point = _DesignSurface.PointToClient(SnapLocation)
            If NewCtlLocation.X + _MoveGlyphXOffset + _MoveGlyphSize < 0 Or NewCtlLocation.Y < 0 Then Exit Sub

            _BoundControl.Location = NewCtlLocation
            RedrawGlyph(VSnapping, VSnapLineStart, VSnapLineEnd, HSnapping, HSnapLineStart, HSnapLineEnd)
        End If
    End Sub

    Private Sub ControlResized(ByVal sender As Object, ByVal e As System.EventArgs)
        RedrawGlyph(False, Nothing, Nothing, False, Nothing, Nothing)
    End Sub
    Private Sub ControlLocationChanged(ByVal sender As Object, ByVal e As System.EventArgs)
        RedrawGlyph(False, Nothing, Nothing, False, Nothing, Nothing)
    End Sub
    Private Sub OnPaint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
        RedrawGlyph(False, Nothing, Nothing, False, Nothing, Nothing)
    End Sub
#End Region
End Class
